<?php

namespace compositePattern;

/**
 * 组合模式的角色和职责
 * 1. 抽象组件(Component)：规定了所有组件(包括基本组件和容器组件)都需要遵循的接口，比如通用的方法。
 * 2. 叶子结点(Leaf)：代表最基本的，不能再分的对象，比如普通员工。叶子结点实现了抽象组件定义的接口，但是不会在包含叶子结点
 * 3. 容器节点(Composite):代表可以包含子组件的对象，比如部门经理。容器节点同样实现了抽象组件接口，同时内部维护着子节点集合，并实现对子节点的添加、删除等操作
 */

// 以文件夹读取为例实现一个组合模式

// 1. 定义抽象组件
interface FileComponent
{
    public function display(string $indent): void;
}

// 定义叶子结点
class FileLeaf implements FileComponent
{
    private string $name;

    /**
     * @param string $name
     */
    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function display(string $indent): void
    {
        echo "$indent -文件：$this->name\n";
    }
}

// 定义容器结点
class FileComposite implements FileComponent
{
    private string $name;
    private array $fileLeafList = [];

    /**
     * @param string $name
     */
    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function display(string $indent): void
    {
        echo "$indent +文件夹：$this->name \n";
        foreach ($this->fileLeafList as $item) {
            if ($item instanceof FileComponent) {
                $item->display("  $indent");
            }
        }
    }

    public function addFileLeaf(FileComponent $fileComponent): void
    {
        $this->fileLeafList[] = $fileComponent;
    }
}

// 测试
// 定义根目录容器
$root = new FileComposite("根目录");
// 想容器中添加节点(文件)和其他层级目录(容器)
// 图片目录
$imageFolder = new FileComposite("图片目录");
// 定义节点(文件)
$image = new FileLeaf('test.png');
$text = new FileLeaf('test.txt');
$doc = new FileLeaf('test.doc');
// 组装
$imageFolder->addFileLeaf($image);
$root->addFileLeaf($imageFolder);
$root->addFileLeaf($text);
$root->addFileLeaf($doc);
$root->display("");